package Entidades;
import TDA.*;
import Implementaciones.*;

public class Tablero {

	MatrizTDA<Barco> tablero;
	int dimensionTablero;
	Vector<Integer> cantOcupadasEnFilas;
	Vector<Integer> cantOcupadasEnColumnas;
	
	
	public Tablero (int n){
		tablero = new Matriz<Barco>();
		this.dimensionTablero = n;
		tablero.inicializarMatriz(n);
		this.cantOcupadasEnColumnas = new Vector<Integer>();
		this.cantOcupadasEnColumnas.inicializarVector(n);
		this.cantOcupadasEnFilas = new Vector<Integer>();
		this.cantOcupadasEnFilas.inicializarVector(n);
	}
	
	public void setearValor(int i, int j, Barco b){
		tablero.setearValor(i, j, b);
	}
	
	public Barco obtenerValor(int i,int j){
		return tablero.obtenerValor(i, j);
	}
	
	public void setearValorEnfila(int i, int cantOcupadaEnF) throws Exception{
		if (i < this.dimensionTablero){
		 this.cantOcupadasEnFilas.agregarElemento(i,cantOcupadaEnF);
		}
	}
	
	public void setearValorEnColumna(int j, int cantOcupadaEnC) throws Exception{
		if (j < this.dimensionTablero){
		 this.cantOcupadasEnColumnas.agregarElemento(j,cantOcupadaEnC);
		}
	}
	
	public int obtenerValorEnfila(int i) throws Exception{
		 return this.cantOcupadasEnFilas.recuperarElemento(i);
	}
	
	public int obtenerValorEnColumna(int j) throws Exception{
		 return this.cantOcupadasEnColumnas.recuperarElemento(j);
	}
	
	public int obtenerDimensionTablero(){
		return this.dimensionTablero;
	
	}
	
	public boolean setearBarco(int i,int j,Barco b){
		if(this.obtenerValor(i, j)==null){
			if(b.obtenerOrientacion() == Orientacion.Horizontal){
				if(j+b.obtenerCantidadCeldas() <= tablero.obtenerDimension()){//chequeo que no me salga del tablero
					for(int f = 0 ; f < b.cantidadCeldas ; f++){
						if(this.obtenerValor(i, j+f)!=null)//chequeo que las posiciones donde voy a setear, no esten llenas.
							return false;
					}
					for(int f = 0 ; f < b.cantidadCeldas ; f++)
						this.setearValor(i, j+f, b);
					return true;
				}
			}
			else{
				if(i+b.obtenerCantidadCeldas() <= tablero.obtenerDimension()){
					for(int c = 0 ; c < b.cantidadCeldas ; c++){
						if(this.obtenerValor(i+c, j)!=null)
							return false;
					}
					for(int c = 0 ; c < b.cantidadCeldas ; c++)
						this.setearValor(i+c, j, b);
					return true;
				}
			}
		}
		return false;
	}
	
	public void imprimirTablero(){
		System.out.println(" ");
		System.out.println(" ");
		for(int fila = 0;fila<dimensionTablero;fila++){
			try {
				System.out.print(this.obtenerValorEnfila(fila) + "   ");
			} catch (Exception e) {
				e.printStackTrace();
			}
			for(int col = 0;col<dimensionTablero;col++){
				Barco b = tablero.obtenerValor(fila, col);
				if(b==null)
					System.out.print(" N ");
				else
					System.out.print(" " + b.obtenerNombre());
			}
			System.out.print("\n");
		}
		System.out.println(" ");
		System.out.print("     ");
		for(int i = 0 ; i < this.dimensionTablero ; i++)
			try {
				System.out.print(this.obtenerValorEnColumna(i) + "  ");
			} catch (Exception e) {
				e.printStackTrace();
			}
		System.out.print("\n\n");		
	}
	
	public boolean validarPosicionesDeBarcos(){
		for(int fila = 0;fila<dimensionTablero;fila++){
			for(int col = 0;col<dimensionTablero;col++){
				Barco b = this.obtenerValor(fila,col);				
				if(b != null){
					if (!this.chequearAlrededoresValidos(b,fila,col)){
						return false;
					}
				}
			}
		}
		return true;
	}
	
	private boolean validarSumaDeBarcos(){
		int[] sumaFila = new int[this.dimensionTablero];
		int[] sumaCol = new int[this.dimensionTablero];
		for(int fila = 0;fila<dimensionTablero;fila++){
			for(int col = 0;col<dimensionTablero;col++){
				Barco b = this.obtenerValor(fila,col);				
				if(b != null){
					sumaFila[fila]++;
					sumaCol[col]++;
				}
			}
		}
		for(int i = 0 ; i<this.dimensionTablero ; i++){
			try {
				if(this.obtenerValorEnfila(i) != sumaFila[i] || this.obtenerValorEnColumna(i) != sumaCol[i])
					return false;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return true;
	}
	
	public boolean validarPosYSuma(){
		if(this.validarSumaDeBarcos() && this.validarPosicionesDeBarcos())
			return true;
		return false;
	}

	public boolean chequearAlrededoresValidos(Barco b, int f, int c) {
		//System.out.println("Comenzando a analizar a " + b.obtenerNombre() + " en " + f + "-" + c) ;
		for(int fila = -1;fila<2;fila++){
			for(int col = -1;col<2;col++){
				//System.out.println("Fila " + (f+fila) + " Col " + (c+col)) ;
				if(f+fila>=0 && f+fila<dimensionTablero){//Posicion dentro del tablero. No me voy de los limites.
					if(c+col>=0 && c+col<dimensionTablero){
						Barco x = this.obtenerValor(f+fila, c+col);
						if(x != null && !x.obtenerNombre().equals(b.obtenerNombre())){
								//System.out.println("Encontre posicion invalida.");
								return false;
						}
					}
				}
			}
		}
		return true;
	}

	public void quitarBarco(int fila, int col, Barco b) {
		for(int i = 0 ; i < b.obtenerCantidadCeldas() ; i++){
			if (b.obtenerOrientacion()==Orientacion.Horizontal)
				tablero.setearValor(fila, col+i, null);
			else
				tablero.setearValor(fila+i, col, null);				
		}
	}
}
